//! Raft in-memory log & state machine scaffold.
//! This isolates storage concerns from `raft.rs` so we can iteratively implement
//! OpenRaft storage traits without destabilizing higher-level logic.

use crate::cluster::ManagedNode;
use crate::raft::{Request, Response, TypeConfig};
use crate::{Error, NodeId, Result};
use openraft::{Entry, LogId, RaftTypeConfig};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::collections::VecDeque;
use std::sync::Arc;

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SmSnapshotMeta {
    pub last_applied: Option<LogId<NodeId>>,
    pub managed_len: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct StateMachineData {
    pub managed: Vec<ManagedNode>,
    pub config: serde_json::Value,
}

#[derive(Clone)]
pub struct InMemStore {
    pub node_id: NodeId,
    log: Arc<RwLock<VecDeque<Entry<TypeConfig>>>>,
    sm: Arc<RwLock<StateMachineData>>,
    last_applied: Arc<RwLock<Option<LogId<NodeId>>>>,
}

impl InMemStore {
    pub fn new(node_id: NodeId) -> Self {
        Self {
            node_id,
            log: Arc::new(RwLock::new(VecDeque::new())),
            sm: Arc::new(RwLock::new(StateMachineData {
                managed: Vec::new(),
                config: serde_json::json!({}),
            })),
            last_applied: Arc::new(RwLock::new(None)),
        }
    }

    pub fn apply(&self, entry: &Entry<TypeConfig>) -> Result<Response> {
        if let openraft::EntryPayload::Normal(ref req) = entry.payload {
            match req {
                Request::AddManagedNode { node } => {
                    self.sm.write().managed.push(node.clone());
                    return Ok(Response::Success);
                }
                Request::RemoveManagedNode { node_id } => {
                    let mut sm = self.sm.write();
                    let before = sm.managed.len();
                    sm.managed.retain(|n| n.id != *node_id);
                    if before == sm.managed.len() {
                        return Ok(Response::Error {
                            message: format!("Node {} not found", node_id),
                        });
                    }
                    return Ok(Response::Success);
                }
                Request::UpdateNodeStatus { .. } => {
                    return Ok(Response::Success);
                }
                Request::UpdateConfiguration { config } => {
                    self.sm.write().config = config.clone();
                    return Ok(Response::Success);
                }
            }
        }
        Ok(Response::Success)
    }

    pub fn get_managed(&self) -> Vec<ManagedNode> {
        self.sm.read().managed.clone()
    }

    pub fn add_managed(&self, node: ManagedNode) {
        self.sm.write().managed.push(node);
    }

    pub fn remove_managed(&self, node_id: &str) {
        let mut sm = self.sm.write();
        sm.managed.retain(|n| n.id != node_id);
    }
}
